package com.idp.controller;

import com.idp.config.ServerProperty;
import com.idp.metadata.MetadataBean;
import com.idp.saml.AuthnRequestResolution;
import com.idp.saml.SAMLResponseResolution;
import com.idp.util.JTRStaticUtils;
import org.opensaml.saml2.core.AuthnRequest;
import org.opensaml.saml2.core.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

@RestController
public class AuthRequestController {

    private static final String SP_METADATA_PATH = ServerProperty.getServerInstance().getProperty("spMetadataPath");

    private static final Logger logger = LoggerFactory.getLogger(AuthRequestController.class);


    /**
     * 基于saml的认证
     */
    @RequestMapping(value = "/idp/redirect")
    public void redirect(HttpServletRequest request, HttpServletResponse response) throws Exception {

        // 目前拥有的HUAWEI云配置的IdP账户的名称
        Map<String, String> idpAuthsMap = JTRStaticUtils.getIdpAuthsMap();
        Collection<GrantedAuthority> authorities = ((UsernamePasswordAuthenticationToken) request.getUserPrincipal()).getAuthorities();
        Map<String, String> responseAssertMap = new HashMap<>();

        if ("eric".equals(request.getRemoteUser())) {    // ** eric是多IAM实现多权限 **

            for (GrantedAuthority ele : authorities) {
                String auth = ele.getAuthority();
                // 若有效权限idpAuthsMap中包含该权限,则 对多权限,赋第一个权限(在数据库中存储的权限越靠前,优先级越高,因此遍历到第一个有效权限即可)
                if (idpAuthsMap.containsKey(auth) && !responseAssertMap.containsKey(JTRStaticUtils.X_USER_ID)) {
                    responseAssertMap.put(JTRStaticUtils.X_USER_ID, idpAuthsMap.get(auth));
                }
            }

        } else {    // ** 其他IdP用户只绑定IAM主账户odder,根据不同xUserId映射到不同权限组 **

            // 和 /index_saml_singleUser 接口中的一样, 只需要最高权限(数据库中的第一个)
            String singleUserAuth = "";
            for (GrantedAuthority ele : authorities) {
                String authority = ele.getAuthority();
                // idp命名与权限命名相同,拥有该命名,则拥有该权限
                if (idpAuthsMap.containsKey(authority)) {
                    singleUserAuth = idpAuthsMap.get(authority);
                    break;
                }
            }
            responseAssertMap.put(JTRStaticUtils.X_USER_ID, singleUserAuth);
        }


        AuthnRequestResolution authnRequestResolution = new AuthnRequestResolution(request);
        try {
            /* 解析SAMLRequest */
            AuthnRequest authnRequest = authnRequestResolution.resolve(request);
            logger.debug("resolve authnRequest successfully!");
            System.out.println("resolve authnRequest successfully!");

            /* SAMLRequest验签 */
            MetadataBean spMetadata = new MetadataBean(SP_METADATA_PATH);
            logger.debug("get SP metadata successfully!");
            System.out.println("get SP metadata successfully!");
            if (!authnRequestResolution.verifySignature(spMetadata)) {
                throw new Exception("verifySignature error!");
            }
            logger.debug("verify authnRequest signature successfully!");
            System.out.println("verify authnRequest signature successfully!");

            /* 生成SAMLResponse */
            SAMLResponseResolution samlResponseResolution = new SAMLResponseResolution();
            // 里面有添加属性的方法
            Response samlResponse = samlResponseResolution.createSamlResponse(authnRequest, spMetadata, responseAssertMap);
            logger.debug("resolve saml response successfully!");
            System.out.println("resolve saml response successfully!");

            /* 签名 */
            samlResponseResolution.signAssertion(samlResponse);
            logger.debug("sign saml response successfully!");
            System.out.println("sign saml response successfully!");

            /* 发送SAMLResponse */
            samlResponseResolution.send(authnRequest, response, request, samlResponse);
            logger.debug("send saml response successfully!");
            System.out.println("send saml response successfully!");

        } catch (Exception e) {
            logger.error("[error Message] decode SAMLRequest error !", e);
            e.printStackTrace();
            response.setStatus(500);
            response.getWriter().println(e.getMessage());
        }
    }
}
